import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;

public class MyByteParser{
	
	private MySorter sorter;
	private HistoryData history;	
	private MyExtrapolation extrapolator;

	public MyByteParser(MySorter sorter, HashMap<Integer, Integer> stations, HistoryData history) {
		this.sorter = sorter;
		this.history = history;
		extrapolator = new MyExtrapolation();	
	}

	/**
	 * Processes the data coming from the inputstream. 
	 * Catches XML file comming in
	 * Strips the XML file
	 * Puts the stripped data into a data object 
	 * @param inputStream Inputstream from the station
	 */
	public void process(InputStream inputStream) {
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
			
			Data data = null;
			
			String line;
			//Skip the first xml specification line
			reader.readLine();	
			int valueCounter = 0;
			
			String weatherDataBeginTag = "<WEATHERDATA>";
			String weatherDataEndTag = "</WEATHERDATA>";
			String measurementBeginTag = "<MEASUREMENT>";
			String measurementEndTag = "</MEASUREMENT>";
			
			Boolean ignoreFirstLine = true;
			
			while((line = reader.readLine()) != null){
				if(valueCounter == 14){
					history.addData(data);
				}
				else if(ignoreFirstLine){
					line = reader.readLine();
					ignoreFirstLine = false;
				}				
				line = line.trim();				
				if(line.equalsIgnoreCase(measurementBeginTag)){
					data = new Data();
				}
				else if(line.equalsIgnoreCase(measurementEndTag)){						
					//add data to buffer of filewriter
					sorter.add(data);					
					
					//Reset all values for next client
					data = null;
					valueCounter = 0;					
				}				
				else if(line.equalsIgnoreCase(weatherDataBeginTag)){
					
				}
				else if(line.equalsIgnoreCase(weatherDataEndTag)){
					ignoreFirstLine = true;
				}				
				else{
					switch(valueCounter){
						case 0:
							data.setStn(Integer.parseInt(getValue(line, 5)));
						break;
						case 1:
							data.setDate(getValue(line, 6));
						break;
						case 2:
							data.setTime(getValue(line, 6));
						break;
						case 3:
							data.setTemp(extrapolate(3, data.getStn(), Double.parseDouble(getValue(line, 6))));
						break;
						case 4:
							data.setDewp(extrapolate(4, data.getStn(), Double.parseDouble(getValue(line, 6))));
						break;
						case 5:
							data.setStp(extrapolate(5, data.getStn(), Double.parseDouble(getValue(line, 5))));
						break;
						case 6:
							data.setSlp(extrapolate(6, data.getStn(), Double.parseDouble(getValue(line, 5))));
						break;
						case 7:
							data.setVisib(extrapolate(7, data.getStn(), Double.parseDouble(getValue(line, 7))));
						break;
						case 8:
							data.setWdsp(extrapolate(8, data.getStn(), Double.parseDouble(getValue(line, 6))));
						break;
						case 9:
							data.setPrcp(extrapolate(9, data.getStn(), Double.parseDouble(getValue(line, 6))));
						break;
						case 10:
							data.setSndp(extrapolate(10, data.getStn(), Double.parseDouble(getValue(line, 6))));
						break;
						case 11:
							data.setFrshtt(getValue(line, 8));
						break;
						case 12:
							data.setCldc(extrapolate(12, data.getStn(), Double.parseDouble(getValue(line, 6))));
						break;
						case 13:
							data.setWnddir(Integer.parseInt(getValue(line, 8)));
						break;						
					}							
					valueCounter++;
				}	
			}
		
		} catch (IOException e) {
			e.printStackTrace();
		}		
	
	}
	
	/**
	 * Returns the value stripped from XML tags and expanded till required length
	 * @param line The line of text
	 * @param lengthOfTag The required length for the tag
	 * @return value The value with the required length and without the tags
	 */
	public String getValue(String line, int lengthOfTag){
		String value = line.substring(lengthOfTag, line.length() - (lengthOfTag+1));
		if(value.trim().isEmpty()){
			value=""+Integer.MIN_VALUE;
		}
		return value;
	}
	
	/**
	 * Extrapolates by the value with historic data.
	 * @param dataType data type
	 * @param stn station number
	 * @param currentIncoming data value
	 * @return currentIncoming The data after extrapolation
	 */
	public double extrapolate(int dataType, int stn, double currentIncoming){

		extrapolator.clearAll();	
		double current = currentIncoming;
		
		ArrayList<Data> histor = history.getHistory(stn);
		
		if(histor != null){			
			for(Data dataHistory: histor){		
				ArrayList<Object> dataArray = dataHistory.getDataArray();
				extrapolator.addDouble((Double) dataArray.get(dataType));			
			}
			if (currentIncoming == Integer.MIN_VALUE) {				
				double growth = extrapolator.growth();
				double lastInserted = extrapolator.getLastValue();
				
				double answer = current;		
				if(growth > (current - lastInserted)){
					answer = lastInserted + growth;
				}				
				return answer;
			}
			if (dataType == 3) {
				return extrapolator.allowedGrowth(currentIncoming);
			}						
		}
		return currentIncoming;		
	}
}

